package cn.yunbamboos.config;

import cn.yunbamboos.bean.ThreadPoolDynamicTaskExecutor;
import cn.yunbamboos.id.SnowflakeIdGenerator;
import cn.yunbamboos.mybatis.register.GenericMapperRegister;
import cn.yunbamboos.properties.YunbamboosProperties;
import cn.yunbamboos.rest.service.ICustomClassLoader;
import cn.yunbamboos.rest.service.IFilterExecute;
import cn.yunbamboos.rest.service.IInDTOConverter;
import cn.yunbamboos.rest.service.IRestServiceList;
import cn.yunbamboos.rest.service.ISessionContainer;
import cn.yunbamboos.rest.service.auth.AuthenticationListener;
import cn.yunbamboos.rest.service.auth.IAuthenticationListener;
import cn.yunbamboos.rest.service.config.RestServiceConfig;
import cn.yunbamboos.rest.service.converter.FileOutDTOToHttpMessageConverter;
import cn.yunbamboos.rest.service.converter.GenericOutDTOToHttpMessageConverter;
import cn.yunbamboos.rest.service.converter.ImageOutDTOToHttpMessageConverter;
import cn.yunbamboos.rest.service.converter.RequestConverterFileInDTO;
import cn.yunbamboos.rest.service.converter.RequestConverterInDTO;
import cn.yunbamboos.rest.service.converter.RequestConverterJSONInDTO;
import cn.yunbamboos.rest.service.core.CustomClassLoader;
import cn.yunbamboos.rest.service.core.FilterExecute;
import cn.yunbamboos.rest.service.core.InDTOConverter;
import cn.yunbamboos.rest.service.core.ReadRestService;
import cn.yunbamboos.rest.service.core.RestServiceInvoke;
import cn.yunbamboos.rest.service.core.RestServiceList;
import cn.yunbamboos.rest.service.dto.IInDTOValidator;
import cn.yunbamboos.rest.service.dto.validator.InDTOValidator;
import cn.yunbamboos.rest.service.filter.GlobalRestServiceFilter;
import cn.yunbamboos.rest.service.filter.RestServiceFilter;
import cn.yunbamboos.rest.service.logs.IStorageLogListener;
import cn.yunbamboos.rest.service.logs.LogMetadataManager;
import cn.yunbamboos.rest.service.session.SessionContainer;
import cn.yunbamboos.rest.service.transaction.DefaultServiceTransactionManager;
import cn.yunbamboos.rest.service.transaction.ServiceTransactionManager;
import cn.yunbamboos.token.ITokenContainer;
import cn.yunbamboos.token.ITokenContainerManager;
import cn.yunbamboos.token.TokenContainer;
import cn.yunbamboos.token.TokenContainerManager;
import cn.yunbamboos.webfilter.GlobalWebFilter;
import jakarta.servlet.Filter;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.boot.autoconfigure.MybatisAutoConfiguration;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.SchedulingConfigurer;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;
import org.springframework.transaction.support.DefaultTransactionDefinition;
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;

import java.util.List;
import java.util.concurrent.ThreadPoolExecutor;

@Configuration
@EnableConfigurationProperties({YunbamboosProperties.class})
@AutoConfigureAfter({MybatisAutoConfiguration.class})
@ComponentScan("cn.yunbamboos.rest.service.dispatcher")
@EnableAsync(proxyTargetClass = true)
public class YunbamboosAutoConfiguration implements SchedulingConfigurer {

    private static final Logger logger = LoggerFactory.getLogger(YunbamboosAutoConfiguration.class);

    private final YunbamboosProperties properties;
    private final DataSourceTransactionManager dataSourceTransactionManager;
    private final DefaultTransactionDefinition transactionDefinition;

    public YunbamboosAutoConfiguration(YunbamboosProperties properties,
                                       DataSourceTransactionManager dataSourceTransactionManager,
                                       DefaultTransactionDefinition transactionDefinition){
        this.properties = properties;
        this.dataSourceTransactionManager = dataSourceTransactionManager;
        this.transactionDefinition = transactionDefinition;
    }

    /**
     * 自定义类加载器
     */
    @Bean
    public ICustomClassLoader createCustomClassLoader() {
        ClassLoader parent = this.getClass().getClassLoader();
        logger.info("service classloader parent {}", parent);
        return new CustomClassLoader(parent, false);
    }

    /**
     * 任务线程池
     * */
    @Bean("TaskExecutor")
    public ThreadPoolTaskExecutor taskExecutor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(properties.getTaskThread().getCorePoolSize());
        executor.setMaxPoolSize(properties.getTaskThread().getMaxPoolSize());
        executor.setQueueCapacity(properties.getTaskThread().getQueueCapacity());
        executor.setKeepAliveSeconds(properties.getTaskThread().getKeepAliveTime());
        executor.setThreadNamePrefix(properties.getTaskThread().getThreadNamePrefix());
        // 线程池对拒绝任务的处理策略
        // CallerRunsPolicy：由调用线程（提交任务的线程）处理该任务
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        // 初始化
        executor.initialize();
        return executor;
    }

    /**
     * 动态任务线程池
     * */
    @Bean("DynamicTaskExecutor")
    public ThreadPoolDynamicTaskExecutor dynamicTaskExecutor() {
        int corePoolSize = properties.getDynamicTaskThread().getCorePoolSize();
        String threadNamePrefix = properties.getDynamicTaskThread().getThreadNamePrefix();
        return new ThreadPoolDynamicTaskExecutor(corePoolSize, threadNamePrefix);
    }

    /**
     * 定时任务线程池
     * */
    @Override
    public void configureTasks(ScheduledTaskRegistrar taskRegistrar) {
        int corePoolSize = properties.getScheduledTaskThread().getCorePoolSize();
        String threadNamePrefix = properties.getScheduledTaskThread().getThreadNamePrefix();

        ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();
        // 设置线程池大小
        taskScheduler.setPoolSize(corePoolSize);
        // 线程名称前缀
        taskScheduler.setThreadNamePrefix(threadNamePrefix);
        // 设置终止时等待最大时间，单位s，即在关闭时，需等待其他任务完成执行
        taskScheduler.setAwaitTerminationSeconds(5);
        // 设置关机时是否等待计划任务完成，不中断正在运行的任务并执行队列中的所有任务，默认false
        taskScheduler.setWaitForTasksToCompleteOnShutdown(false);

        // 线程池对拒绝任务的处理策略
        // CallerRunsPolicy：由调用线程（提交任务的线程）处理该任务
        taskScheduler.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());

        taskScheduler.initialize();
        taskRegistrar.setScheduler(taskScheduler);
    }

    @Bean
    public RestServiceConfig createRestServiceConfig(){
        return new RestServiceConfig(properties);
    }

    @Bean
    public GenericMapperRegister createGenericMapperRegister(SqlSessionFactory sessionFactory){
        GenericMapperRegister register = new GenericMapperRegister(sessionFactory.getConfiguration());
        register.register();
        return register;
    }

    /**
     * 日志元数据
     */
    @Bean
    public LogMetadataManager createLogMetadataManager(List<IStorageLogListener> listeners) {
        return new LogMetadataManager(listeners);
    }

    @Bean
    public InDTOValidator createInDTOValidator(LocalValidatorFactoryBean localValidatorFactoryBean) {
        return new InDTOValidator(localValidatorFactoryBean);
    }

    /**
     * session容器
     */
    @Bean
    public ISessionContainer createSessionContainer() {
        return new SessionContainer();
    }

    /**
     * 雪花ID生成
     */
    @Bean
    public SnowflakeIdGenerator createSnowflakeIdGenerator() {
        return new SnowflakeIdGenerator();
    }

    /**
     * token容器
     */
    @Bean
    public ITokenContainer createTokenContainer() {
        return new TokenContainer();
    }

    /**
     * token管理
     */
    @Bean
    public ITokenContainerManager createTokenContainerManager(ITokenContainer tokenContainer) {
        return new TokenContainerManager(tokenContainer);
    }

    /**
     * 默认的权限认证
     */
    @Bean
    public IAuthenticationListener createAuthenticationListener(ITokenContainer tokenContainer) {
        return new AuthenticationListener(tokenContainer);
    }

    /**
     * 通用的OutDTO转String
     */
    @Bean
    public GenericOutDTOToHttpMessageConverter createGenericOutDTOToStringConverter() {
        return new GenericOutDTOToHttpMessageConverter();
    }

    @Bean
    public ImageOutDTOToHttpMessageConverter createImageOutDTOToHttpMessageConverter() {
        return new ImageOutDTOToHttpMessageConverter();
    }

    @Bean
    public FileOutDTOToHttpMessageConverter createFileOutDTOToHttpMessageConverter() {
        return new FileOutDTOToHttpMessageConverter();
    }

    @Bean
    public RequestConverterFileInDTO createRequestConverterFileInDTO() {
        return new RequestConverterFileInDTO();
    }

    @Bean
    public RequestConverterJSONInDTO createRequestConverterJSONInDTO() {
        return new RequestConverterJSONInDTO();
    }

    @Bean
    public FilterExecute createFilterExecute(ApplicationContext applicationContext, List<GlobalRestServiceFilter> globalFilters) {
        return new FilterExecute(applicationContext, globalFilters);
    }

    @Bean
    public InDTOConverter createInDTOConverter(ISessionContainer sessionContainer, List<RequestConverterInDTO> requestConverters) {
        return new InDTOConverter(sessionContainer, requestConverters);
    }

    @Bean
    public ServiceTransactionManager createServiceTransactionManager() {
        return new DefaultServiceTransactionManager(dataSourceTransactionManager, transactionDefinition);
    }

    @Bean
    public IRestServiceList createRestServiceList() {
        return new RestServiceList();
    }

    @Bean
    public RestServiceInvoke createRestServiceInvoke(IInDTOConverter converter,
                                                     IFilterExecute filterExecute,
                                                     ISessionContainer sessionContainer,
                                                     List<IAuthenticationListener> authenticationListeners,
                                                     ServiceTransactionManager serviceTransactionManager,
                                                     IInDTOValidator validator) {
        return new RestServiceInvoke(converter,
                filterExecute,
                sessionContainer,
                authenticationListeners,
                serviceTransactionManager,
                validator);

    }

    @Bean
    public ReadRestService createReadRestService(ApplicationContext applicationContext, IRestServiceList restServiceList, ICustomClassLoader customClassLoader){
        return new ReadRestService(properties.getProjectPath(), properties.getRestServicePath(), applicationContext, restServiceList, customClassLoader);
    }

    @Bean // 标注为Spring配置bean组件
    public FilterRegistrationBean<Filter> registerGlobalWebFilter(ApplicationEventPublisher applicationEventPublisher) {
        //通过FilterRegistrationBean实例设置优先级可以生效
        FilterRegistrationBean<Filter> registrationBean = new FilterRegistrationBean<>();
        // 注册自定义过滤器
        registrationBean.setFilter(new GlobalWebFilter(applicationEventPublisher));
        // 设置过滤器的名字<filter-name>
        registrationBean.setName("global-web-filter");
        // 设置过滤器的名字过滤路径<url-partten>
        registrationBean.addUrlPatterns("/*");
        // 设置过滤器优先级：最顶级
        registrationBean.setOrder(1);
        return registrationBean;
    }

}
